package com.come4loves.game.module.actor.handler;

import io.netty.channel.ChannelHandlerContext;

import java.util.HashMap;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import org.springframework.util.Base64Utils;

import com.come4loves.core.comunicate.protocol.Response;
import com.come4loves.core.comunicate.router.annotation.Cmd;
import com.come4loves.core.result.BytesResult;
import com.come4loves.core.result.TResult;
import com.come4loves.core.utils.StringUtils;
import com.come4loves.core.utils.TimeUtils;
import com.come4loves.game.constent.GameStatusCodeConstant;
import com.come4loves.game.dbproxy.entity.Actor;
import com.come4loves.game.module.actor.helper.UserPushHelper;
import com.come4loves.game.module.actor.service.ActorService;
import com.come4loves.game.module.actor.service.UserSerivce;
import com.come4loves.game.proto.ActorProto;
import com.come4loves.game.proto.ModuleName;
import com.come4loves.game.proto.UserCmd;
import com.come4loves.game.server.router.GatewayRouterHandlerImpl;
import com.come4loves.game.server.session.PlayerContext;
import com.come4loves.game.server.session.UserReconnectData;
import com.google.protobuf.InvalidProtocolBufferException;

@Component
public class ActorHanlder extends GatewayRouterHandlerImpl {
	@Autowired
	protected PlayerContext playerContext;
	
	@Autowired
	private UserSerivce userService;
	@Autowired
	@Qualifier("game.server.id")
	private int serverId;
	@Autowired
	@Qualifier("game.server.debug")
	private boolean debugMode ;
	@Autowired
	@Qualifier("game.server.version")
	private String version ;
	@Autowired
	private ActorService actorService;
	
	
	@Override
	public byte getModule() {
		return ModuleName.Module.USER_VALUE;
	}
	@Cmd(id = UserCmd.User.HEART_BEAT_VALUE,checkActorLogin =  false)
	public BytesResult heartBeat(ChannelHandlerContext context,byte[] bytes, Response response) {
		ActorProto.HeartBeatResponse.Builder builder = ActorProto.HeartBeatResponse.newBuilder();
		builder.setTimeNow(TimeUtils.getNow());
		return BytesResult.sucess(builder.build().toByteArray());
	}
	@Cmd(id = UserCmd.User.USER_LOGIN_VALUE,checkActorLogin =  false)
	public void userLogin(ChannelHandlerContext context,byte[] bytes, Response response) {
		ActorProto.UserLoginRequest request = null;
		try {
			request = ActorProto.UserLoginRequest.parseFrom(bytes);
		} catch (InvalidProtocolBufferException e) {
			LOGGER.error("{}", e);
		}
		String token = request.getToken();
		if (StringUtils.isBlank(token)) {
			UserPushHelper.userLoginFail(context,response, GameStatusCodeConstant.TOKEN_VALIDATE_ERROR);
			return;
		}
		if (request.getServerId() != serverId){
			UserPushHelper.userLoginFail(context,response,GameStatusCodeConstant.SERVER_ID_ERROR);
			return;
		}
		String channel = request.getChannel();
		if (debugMode){
			String reconnectId = playerContext.setLoginData(token);
			playerContext.setUserLogin(context, channel, token);
			long actorId = actorService.getActorId(request.getToken());
			UserPushHelper.userLoginSucces(context, response,token, serverId, actorId, reconnectId);
			return;
		}
		
		Map<String, String> params = new HashMap<String, String>();
		params.put("token", token);
		userService.putUserLoginQueue(context,response,request.getChannel(), params);
		
	}
	@Cmd(id = UserCmd.User.CREATE_ACTOR_VALUE,checkActorLogin =  false)
	public BytesResult createActor(ChannelHandlerContext context,byte[] bytes, Response response) {
		String uid = playerContext.getUid(context);
		if (StringUtils.isBlank(uid)) {
			return BytesResult.valueOf(GameStatusCodeConstant.USER_LOGIN_ERROR);
		}
		if (actorService.isExsitActor(uid)) {
			return BytesResult.valueOf(GameStatusCodeConstant.DENY_CREATE_ACTOR);
		}
		
		long actorId = actorService.createActor();
		actorService.uidBindActor(uid, actorId);
		ActorProto.CreateActorResponse.Builder builder = ActorProto.CreateActorResponse.newBuilder();
		builder.setActorId(actorId);
		return BytesResult.sucess(builder.build().toByteArray());
		
		
	}
	@Cmd(id = UserCmd.User.ACTOR_LOGIN_VALUE, checkActorLogin = false)
	public void actorLogin(ChannelHandlerContext context,byte[] bytes, Response response) throws Exception{
		ActorProto.ActorLoginRequest request = ActorProto.ActorLoginRequest.parseFrom(bytes);
		long actorId = request.getActorId();
		Actor actor = actorService.getActor(actorId);
		if (actor == null) {
			response.setStatusCode(GameStatusCodeConstant.ACTOR_ID_VALIDATE_ERROR);
			sessionWrite(context, response);
			return;
		}
		if (playerContext.isOnline(actorId)) {
			//TODO
			ChannelHandlerContext online = playerContext.getOnlineContext(actorId);
			UserPushHelper.kickoff(online, GameStatusCodeConstant.ACTOR_LOGIN_DUPLICATE);
		}
		playerContext.put2OnlineList(actorId, context);
		ActorProto.ActorLoginResponse.Builder builder = ActorProto.ActorLoginResponse.newBuilder();
		builder.setActorId(actorId);
		response.setValue(builder.build().toByteArray());
		sessionWrite(context, response);
		
	}
	
	
	@Cmd(id = UserCmd.User.RECONNECT_VALUE,checkActorLogin =  false)
	public BytesResult reconnect(ChannelHandlerContext context,byte[] bytes, Response response) throws Exception{
		ActorProto.ReconnectRequest request = ActorProto.ReconnectRequest.parseFrom(bytes);
		TResult<UserReconnectData> result = playerContext.validateReconnect(request.getReconnectId(), request.getVersion());
		if (result.isFail()) {
			return BytesResult.valueOf(result.statusCode);
		}
		long actorId = actorService.getActorId(result.item.getUid());
		Actor actor = actorService.getActor(actorId);
		playerContext.setServerId(context, serverId);
		playerContext.put2OnlineList(actor.getPkId(), context); // 正式转正在线Session管理
		
		ActorProto.UserLoginResponse.Builder builder = ActorProto.UserLoginResponse.newBuilder();
		builder.setActorId(actor.getPkId());
		builder.setServerId(serverId);
		builder.setUid(result.item.getUid());
		builder.setReconnectId(result.item.getReconnectId());
		return BytesResult.sucess(builder.build().toByteArray());
	}
	@Cmd(id = UserCmd.User.GET_BIND_CODE_VALUE,checkActorLogin =  false)
	public BytesResult getBindCode(ChannelHandlerContext context,byte[] bytes, Response response) throws Exception{
		String uid = playerContext.getUid(context);
		if (StringUtils.isBlank(uid)) {
			return BytesResult.valueOf(GameStatusCodeConstant.USER_LOGIN_ERROR);
		}
		long actorId = actorService.getActorId(uid);
		int expire = 120000;
		String uuid = actorId + "#" +System.currentTimeMillis();
		String code = Base64Utils.encodeToString(uuid.getBytes());
		ActorProto.GetActorCodeResponse.Builder builder = ActorProto.GetActorCodeResponse.newBuilder();
		builder.setCode(code);
		builder.setExpire(expire/1000);
		return BytesResult.sucess(builder.build().toByteArray());
	}
	@Cmd(id = UserCmd.User.BIND_ACTOR_VALUE,checkActorLogin =  false)
	public BytesResult bindCode(ChannelHandlerContext context,byte[] bytes, Response response) throws Exception{
		String uid = playerContext.getUid(context);
		if (StringUtils.isBlank(uid)) {
			return BytesResult.valueOf(GameStatusCodeConstant.USER_LOGIN_ERROR);
		}
		ActorProto.BindCodeRequest request = ActorProto.BindCodeRequest.parseFrom(bytes);
		String code = request.getCode();
		byte[] temp = Base64Utils.decodeFromString(code);
		String value = new String(temp);
		String[] result = value.split("#");
		if (result.length != 2) {
			return BytesResult.valueOf(GameStatusCodeConstant.BIND_FAIL);
		}
		if (System.currentTimeMillis() - Long.valueOf(result[1]) <= 0) {
			return BytesResult.valueOf(GameStatusCodeConstant.BIND_CODE_EXPIRE);
		}
		long actorId = Long.valueOf(result[0]);
		
		boolean flag = actorService.uidBindActor(uid, actorId);
		if (!flag) {
			return BytesResult.valueOf(GameStatusCodeConstant.ACTOR_NOT_FOUND);
		}
	
		ActorProto.BindCodeRespone.Builder builder = ActorProto.BindCodeRespone.newBuilder();
		builder.setActorId(actorId);
		return BytesResult.sucess(builder.build().toByteArray());
	}
	
}
